define ['fizz', 'view/BootstrapView', 'knockback', 'knockout'],  (fizz, BootstrapView, kb, ko) ->
  class ListView extends BootstrapView
  
    # Events.
    events: {
      'submit form.search': 'search',
      'click button.clean': 'clean',
      'click .gopage': 'gopage',
      'click button.cancel': 'cancel',
      'click button.return': 'cancel',
      'click button.view': 'view',
      'click button.add': 'add',
      'click button.edit': 'edit',
      'click button.delete': 'del',
      'click button.select': 'select',
      'click button.validate': 'validate',
      'click button.nothing': 'nothing'
    }
    
    constructor: ->
      super()
      # Collection instance. Override it with your own.
      @collection = null
      # Search model instance. Override it with your own.
      @searchModel = null
      # Number of item per page. Override it with your own.
      @numPerPage = 3
      # Selected objects attributes for selection/multiselection
      @selectedObjectsAttr = []
      # Selected ids for selection/multiselection
      @selectedIds = []
      
    compileTemplate: (params) ->
      super(params)
        
    # Render the template.
    renderTemplate: (params) ->
      @collection = params.collection if _.isObject params.collection
      if _.isArray params.selectedObjectsAttr
        @selectedObjectsAttr = params.selectedObjectsAttr
        @selectedIds = _.pluck @selectedObjectsAttr, 'id'
      @page = if _.isFinite params.page then params.page else 0

      searchString = null;
      if _.isObject @searchModel
        searchString = JSON.stringify @searchModel.toJSON()

      if _.isObject @collection
        # Fetch collection
        @collection.fetch {
          cache: false,
          data: {page: @page, size: @numPerPage, search: searchString},
          success: (collection) =>
            @listLoaded = true
            @$el.html @template {messages: @messages, collection: collection, action: @action, params: params, selectedIds: @selectedIds}
            @bindSearchModel params
        }

    # bind the search model.
    bindSearchModel: (params) ->
      if _.isObject @viewModel
        @viewModel.destroy
      if _.isObject @searchModel
        @viewModel = kb.viewModel @searchModel
        ko.applyBindings @viewModel, @$el[0]

    search: (e) ->
      e.preventDefault()
      @mediator.publish 'message', 'clear'
      if _.isObject @searchModel
        @render {el: @el}

    clean: (e) ->
      @$el.find('input[type=text]').val('').change()
      @search e
            
    gopage: (e) ->
      e.preventDefault()
      @mediator.publish 'message', 'clear'
      @render {page: $(e.target).data('page')}
            
    view: (e) ->
      e.preventDefault()
      elem = @$ e.target
      fizz.utils.navigate @routeToNavigate + '/view/' + elem.data 'id'
            
    add: (e) ->
      e.preventDefault()
      fizz.utils.navigate @routeToNavigate + '/add'
        
    edit: (e) ->
      elem = @$ e.target
      fizz.utils.navigate @routeToNavigate + '/edit/' + elem.data 'id'
        
    del: (e) ->
      elem = @$ e.target
      fizz.utils.navigate @routeToNavigate + '/delete/' + elem.data 'id'
        
    select: (e) ->
      elem = @$ e.target
      id = elem.data 'id'
      if @action is 'select'
        @mediator.publish 'select', id, @collection.model.extend()
        @remove()
      else if @action is 'multiselect'
        if -1 is _.indexOf @selectedIds, id
          @selectedIds.push id
          @selectedObjectsAttr.push @collection.get(id).attributes
          elem.addClass 'selected'
        else
          @selectedIds = _.without @selectedIds, id
          @selectedObjectsAttr = _.reject @selectedObjectsAttr, (obj) -> return obj.id is id
          elem.removeClass 'selected'
        
    validate: (e) ->
      if @action is 'multiselect'
        @mediator.publish 'multiselect', _.clone(@selectedObjectsAttr), @collection.model.extend()
        @selectedIds = []
        @selectedObjectsAttr = []
      @remove()
        
    nothing: (e) ->
      if @action is 'select'
        @mediator.publish 'select', null, @collection.model.extend()
      else if 'multiselect' is @action
        @mediator.publish 'multiselect', [], @collection.model.extend()
      @remove()
        
    cancel: (e) ->
      @mediator.publish 'message', 'clear'
      @remove()